package doton_to_bonc

import (
	"encoding/json"
	"errors"
	"lifi"
	"lifi/internal"
	"lifi/plugins/transfers"
	"log"
	"os"
)

const (
	layout       = "2006-01-02 15:04:05"
	goldenLayout = "2006/1/2 15:04:05.000"
)

type CodeType int
type mapping map[string]map[CodeType]string

var (
	environmentInfoMap mapping
)

type EnvironmentData struct {
	Temperature  string `json:"temperature"`
	LowAccTotal  string `json:"lowAccTotal"`
	HighAccTotal string `json:"highAccTotal"`
}

/*
DotonMetrics
eg.{"alarm_level":0,"alarm_noti_time":"0001-01-01 00:00:00","code":112,"node_code":"999001001_7","node_id":"076db662-c11e-4d7e-8593-c11dfbffd3db","sampletime":"2023-09-05 08:36:10","value":0.058425084},
*/
type DotonMetrics struct {
	Sampletime    string  `json:"sampletime" yaml:"sampletime"`
	Code          int     `json:"code" yaml:"code"`
	NodeCode      string  `json:"node_code" yaml:"node_code"`
	AlarmNotiTime string  `json:"alarm_noti_time" yaml:"alarm_noti_time"`
	AlarmLevel    int     `json:"alarm_level" yaml:"alarm_level"`
	Value         float64 `json:"value" yaml:"value"`
	NodeID        string  `json:"node_id" yaml:"node_id"`
}
type MqttValueDto struct {
	Q  int     `json:"q" yaml:"q"`
	T  int64   `json:"t" yaml:"t"`
	V  float64 `json:"v" yaml:"v"`
	ID string  `json:"id" yaml:"id"`
}
type BoncMqttDto struct {
	Values    []MqttValueDto `json:"values" yaml:"values"`
	Timestamp int64          `json:"timestamp" yaml:"timestamp"`
}
type Donet2BoncTransfer struct {
	MappingFile string `json:"mappingFile" yaml:"mappingFile"`
}

func (d *Donet2BoncTransfer) Init() error {
	var (
		environmentInfo map[string]EnvironmentData
	)
	mappingData, err := os.ReadFile(d.MappingFile)
	if err != nil {
		log.Printf("Exit! Cause cannot open Config file : %v", err)
	}

	err = json.Unmarshal(mappingData, &environmentInfo)
	if err != nil {
		log.Printf("Exit! Cause invalid config MappingFile :%s", d.MappingFile)
	}
	environmentInfoMap = convertEnvironmentInfo(environmentInfo)
	return err
}

func convertEnvironmentInfo(info map[string]EnvironmentData) mapping {
	var r = make(mapping)
	for k, v := range info {
		res := map[CodeType]string{
			100: v.Temperature,
			101: v.LowAccTotal,
			112: v.HighAccTotal,
		}
		r[k] = res
	}
	return r

}
func (d *Donet2BoncTransfer) Start(_ lifi.Collector) error {
	return nil
}

func (d *Donet2BoncTransfer) Stop() {
}

func (d *Donet2BoncTransfer) Process(data lifi.Data, acc lifi.Collector) error {
	var dotonMetrics []DotonMetrics
	if bd, ok := data.(lifi.ByteData); ok {
		err := json.Unmarshal(bd.Data, &dotonMetrics)
		if err != nil {
			log.Printf("解析JSON时发生错误:%v", err)
			return err
		}

		mqttDto, err := metricToMqtt(dotonMetrics)
		if err != nil {
			log.Printf("convert metric To Mqtt时发生错误:%v", err)
			return err
		}
		bytes, err := json.Marshal(&mqttDto)

		if err != nil {
			log.Printf("MqttDto 序列化时发生错误:%v", err)
			return err
		}

		acc.Collect(lifi.NewByteData(bytes, string(data.Group())))
		return nil
	}

	return errors.New(string("unknow data:" + data.Group()))
}

var _ lifi.Transfer = &Donet2BoncTransfer{}

func init() {
	transfers.Add("doton_to_bonc", func() lifi.Transfer {
		return &Donet2BoncTransfer{}
	})
}
func metricToMqtt(metrics []DotonMetrics) (*BoncMqttDto, error) {
	if len(metrics) == 0 {
		return nil, errors.New("metrics is empty")
	}
	tsStr := metrics[0].Sampletime
	ts, err := internal.Str2Timestamp(tsStr)
	if err != nil {
		return nil, err
	}
	values := make([]MqttValueDto, 0)
	for _, k := range metrics {
		sensorCode, exists := environmentInfoMap[k.NodeCode][CodeType(k.Code)]
		if !exists {
			continue
		}
		values = append(values, MqttValueDto{Q: 1, T: ts, V: k.Value, ID: sensorCode})
	}
	res := BoncMqttDto{
		Timestamp: ts,
		Values:    values,
	}

	return &res, nil

}
